using System;
using System.Collections.Generic;
using Sce.Pss.Core.Graphics;
using Sce.Pss.HighLevel.GameEngine2D;
using Sce.Pss.HighLevel.GameEngine2D.Base;
using Sce.Pss.Core;
using Sce.Pss.Core.Environment;

using Sce.Pss.Core.Imaging;
using Sce.Pss.Core.Input;

namespace RedSkies
{
	public class WorldMatrix:IWorldMatrix
	{
		protected List<List<byte?>> Map = new List<List<byte?>>();		
				
		protected Dictionary<string, WorldSprite> MapSprites = new Dictionary<string, WorldSprite>();
		
		public byte TileSize {get; set;}
		
		public List<SpriteList> SpriteListMap = new List<SpriteList>();
		public List<TextureInfo> ListOfTextures= new List<TextureInfo>();
		
		public WorldMatrix (int maxX, int maxY, byte tilesize)
		{
			this.TileSize=tilesize;
			for (int x=0;x<maxX;x++)
			{	
				List<byte?> liste = new List<System.Nullable<byte>>();
				for (int y=0;y<maxY;y++)
				{
					liste.Add(0);	
				}
				Map.Add(liste);
			}			
		}
		
		public WorldSprite GetWorldspriteAt(int x, int y)
		{
			if (MapSprites.ContainsKey(x + "_" + y))
			{
				return MapSprites[x + "_" + y];
			}
			return null;
		}		
		
		public void AddWorldspriteBetween(int x, int xMax, int y, int yMax)
		{
			for (int iX = x;iX<xMax;iX++)
			{
				for (int iY = y;iY<yMax;iY++)
				{					
					AddWorldSprite(iX,iY);
				}
			}			
		}		

		public void AddWorldspriteAt(WorldSprite ws, int x, int y)
		{
			if (!MapSprites.ContainsKey(x + "_" + y))
			{
				MapSprites.Add(x + "_" + y, ws);
			}			
		}
		
		public List<WorldSprite> GetAllWorldspriteBeetween(int x, int xMax, int y, int yMax)
		{
			List<WorldSprite> sprites = new List<WorldSprite>();
			
			for (int iX = x;iX<xMax;iX++)
			{
				for (int iY = y;iY<yMax;iY++)
				{					
					WorldSprite ws = GetWorldspriteAt(iX, iY);
					if (ws!=null)
					{
						sprites.Add(ws);
					}
				}
			}
			return sprites;
		}
		
		public List<byte> GetAllElementsBeetweenGraphicCoordinates(int x, int xMax, int y, int yMax)
		{
			List<byte> elements = new List<byte>();
			List<string> coordinates = new List<string>();
			
			for (int iX = x;iX<=xMax;iX++)
			{
				for (int iY = y;iY<=yMax;iY++)
				{					
					int xE = iX / TileSize;
					int yE = iY / TileSize;
					string keycoordinate = xE + "_" + yE;
					if (!coordinates.Contains(keycoordinate))
					{
						coordinates.Add(keycoordinate);
						if (this[xE, yE]!=null)
						{
							elements.Add((byte)this[xE, yE]);
						}
					}
				}
			}
			return elements;
		}		
		
		public void RemoveAllBetween(int xMatrixOutOfScreenStart,int xMatrixOutOfScreen,int yMatrixOnScreenStart,int yMatrixOnScreenMax)
		{
			foreach (WorldSprite ws in GetAllWorldspriteBeetween(xMatrixOutOfScreenStart,xMatrixOutOfScreen,yMatrixOnScreenStart, yMatrixOnScreenMax))
			{
				ws.Remove();
				MapSprites.Remove(ws.WorldX + "_" + ws.WorldY);				
			}			
		}				
		
		public byte? this[int x, int y]
		{
			get
			{
				if (x<0||y<0)
				{
					return null;
				}
				if (Map.Count-1<x)
				{
					return null;
				}
				if (Map[x].Count-1<y)
				{
					return null;
				}
				return Map[x][y];
			}
			set
			{
				if (Map.Count<x)
				{
					return;	
				}
				if (Map[x].Count<y)
				{
					return;	
				}
				if (x<0||y<0)
				{
					return;	
				}
				Map[x][y] = value;
			}
		}
		
		public byte? GetElementByGraphixCoordinates(int xGraph, int yGraph)
		{
			return this[xGraph/TileSize, yGraph/TileSize];	
		}

		public Rectangle GetHighestSpriteRectangleBetweenGraphixCoordinates(int xGraph, int xGraphMax, int yGraph, int yGraphMax)
		{
			int lowestX = xGraph>xGraphMax? xGraphMax: xGraph;
			int lowestY = yGraph>yGraphMax? yGraphMax: yGraph;

			int highestX = xGraph<xGraphMax? xGraphMax: xGraph;
			int highestY = yGraph<yGraphMax? yGraphMax: yGraph;
			
			for (int iX=highestX;iX>=lowestX;iX--)
			{
				for (int iY=highestY;iY>=lowestY;iY--)
				{
					byte? b = GetElementByGraphixCoordinates(iX,iY);
					if (b!=null && b!=0) 
					{
						return GetWorldspriteAt(iX / TileSize, iY/TileSize).GetRect();	
					}
				}
			}
			return new Rectangle(-999999, -999999, -999999, -999999);
				
		}
		
		public Rectangle GetGraphixRectangleByMapCoordinates(int x, int y)
		{
			return new Rectangle(x*TileSize, y*TileSize,TileSize,TileSize);
		}
		
		protected void AddWorldSprite (int x, int y)
		{
			byte? element = this[x,y];
			if (element==null)
			{
				return;
			}
			byte e=(byte)element;
			SpriteList sL = SpriteListMap[e];
			
			if (!this.MapSprites.ContainsKey(x+"_"+y))
			{
				MapSprites.Add(x+"_"+y, new WorldSprite(ListOfTextures[e], GetGraphixRectangleByMapCoordinates(x,y), SpriteListMap[e], x,y));
			}			
		}
		
		public void CreateInitialWorld()
		{
			for (int x=0;x<(960/TileSize)*1.1;x++)
			{
				for (int y=0;y<(560/TileSize);y++)
				{
					AddWorldSprite (x, y);
				}
			}
		}
		

	}
}

